﻿using PARK.Common.Core.Manager;
using PARK.Common.Enum;
using PARK.Common.Extension;
using PARK.Common.Filter;
using PARK.Common.Util;
using PARK.Dependency;
using PARK.DynamicApiController;
using PARK.FriendlyException;
using PARK.System.Entitys.Dto.Permission.Role;
using PARK.System.Entitys.Permission;
using PARK.System.Entitys.System;
using PARK.System.Interfaces.Permission;
using PARK.System.Interfaces.System;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JNPF.System.Entitys.Dto.Permission.Role;

namespace PARK.System.Service.Permission
{
    /// <summary>
    /// 业务实现：角色信息
    /// </summary>
    [ApiDescriptionSettings(Tag = "Permission", Name = "Role", Order = 167)]
    [Route("api/permission/[controller]")]
    public class RoleService : IRoleService, IDynamicApiController, ITransient
    {
        private readonly ISqlSugarRepository<RoleEntity> _roleRepository;  // 角色表仓储
        private readonly ISqlSugarRepository<UserRelationEntity> _userRelationRepository;
        private readonly IAuthorizeService _authorizeService;
        private readonly ISqlSugarRepository<DictionaryDataEntity> _dictionaryDataRepository;// 数据字典表仓储
        private readonly ISysCacheService _sysCacheService;
        private readonly IUserManager _userManager;
        private readonly SqlSugarScope _db;

        /// <summary>
        /// 初始化一个<see cref="RoleService"/>类型的新实例
        /// </summary>
        public RoleService(ISqlSugarRepository<RoleEntity> roleRepository, ISqlSugarRepository<DictionaryDataEntity> dictionaryDataRepository, ISqlSugarRepository<UserRelationEntity> userRelationRepository, IAuthorizeService authorizeService, ISysCacheService sysCacheService, IUserManager userManager)
        {
            _roleRepository = roleRepository;
            _authorizeService = authorizeService;
            _userRelationRepository = userRelationRepository;
            _dictionaryDataRepository = dictionaryDataRepository;
            _sysCacheService = sysCacheService;
            _userManager = userManager;
            _db = _roleRepository.Context;
        }

        #region GET
        /// <summary>
        /// 获取列表(各租户管理员使用)
        /// </summary>
        /// <param name="input">参数</param>
        /// <returns></returns>
        [HttpGet("")]
        public async Task<dynamic> GetList([FromQuery] RoleListQuery input)
            {
                var userInfo = await _userManager.GetUserInfo();
                var sidx = input.sidx == null ? "sortCode" : input.sidx;
                var data = await _db.Queryable<RoleEntity>()
                    .Where(t => t.DeleteMark == 0 && t.CompanyId == userInfo.companyId && t.IsSysCreate==0)
                    .WhereIF(!string.IsNullOrEmpty(input.keyword), t => t.FullName.Contains(input.keyword) || t.CompanyName.Contains(input.keyword))
                    .Select(a => new RoleListOutput
                    {
                        id = a.Id,
                        fullName = a.FullName,
                        enCode =a.EnCode,
                        description = a.Description,
                        enabledMark = a.EnabledMark,
                        sortCode = a.SortCode,
                        deleteMark = a.DeleteMark,
                        companyId = a.CompanyId,
                        companyName = a.CompanyName,
                        creatorTime = a.CreatorTime,
                        isSys = a.IsSys,
                        isDefault = a.IsDefault,
                        roletype = a.Roletype,
                        isSysCreate = a.IsSysCreate
                    }).MergeTable().OrderBy(sidx + " " + input.sort).ToPagedListAsync(input.currentPage, input.pageSize);
                return PageResult<RoleListOutput>.SqlSugarPageResult(data);
        }
        /// <summary>
        /// 获取租户角色列表(平台超级管理员使用)
        /// </summary>
        /// <param name="input">参数</param>
        /// <returns></returns>
        [HttpGet("GetcompanyRoleList")]
        public async Task<dynamic> GetshoolRoleList([FromQuery] RoleListQuery input)
        {
            var userInfo = await _userManager.GetUserInfo();
            var sidx = input.sidx == null ? "sortCode" : input.sidx;
            var data = await _db.Queryable<RoleEntity>()
                .Where(t => t.DeleteMark == 0 && t.IsAdmin == 1 && t.IsSysCreate == 1 && t.Roletype==2 && t.Type == "CompanyAdminRole")
                .WhereIF(!string.IsNullOrEmpty(input.keyword), t => t.FullName.Contains(input.keyword) || t.CompanyName.Contains(input.keyword))
                .Select(a => new RoleListOutput
                {
                    id = a.Id,
                    fullName = a.FullName,
                    enCode = a.EnCode,
                    description = a.Description,
                    enabledMark = a.EnabledMark,
                    sortCode = a.SortCode,
                    deleteMark = a.DeleteMark,
                    companyId = a.CompanyId,
                    companyName = a.CompanyName,
                    creatorTime = a.CreatorTime,
                    isSys = a.IsSys,
                    isDefault = a.IsDefault,
                    roletype = a.Roletype,
                    isSysCreate = a.IsSysCreate
                }).MergeTable().OrderBy(sidx + " " + input.sort).ToPagedListAsync(input.currentPage, input.pageSize);
            return PageResult<RoleListOutput>.SqlSugarPageResult(data);
        }


        /// <summary>
        /// 获取下拉框(类型+角色)
        /// </summary>
        /// <returns></returns>
        [HttpGet("Selector")]
        public async Task<dynamic> GetSelector()
        {
            var userInfo = await _userManager.GetUserInfo();
            var data = await _db.Queryable<RoleEntity>()
                    .Where(t => t.DeleteMark == 0 && t.CompanyId == userInfo.companyId)
                    .Select(a => new RoleListOutput
                    {
                        id = a.Id,
                        fullName = a.FullName
                    }).MergeTable().ToListAsync();
            return new { list = data };
        }

        /// <summary>
        /// 获取信息
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        [HttpGet("{id}")]
        public async Task<dynamic> GetInfo(string id)
        {
            var entity = await _roleRepository.FirstOrDefaultAsync(r => r.Id == id);
            var output = entity.Adapt<RoleInfoOutput>();
            return output;
        }
        #endregion

        #region POST
        /// <summary>
        /// 新建
        /// </summary>
        /// <param name="input">参数</param>
        /// <returns></returns>
        public async Task Create([FromBody] RoleCrInput input)
        {
            var userInfo = await _userManager.GetUserInfo();
            if (await _roleRepository.AnyAsync(r => r.EnCode == input.enCode && r.DeleteMark == 0 && r.CompanyId ==userInfo.companyId))
                throw PARKException.Oh(ErrorCode.D1600);
            if (await _roleRepository.AnyAsync(r => r.FullName == input.fullName && r.DeleteMark == 0 && r.CompanyId ==userInfo.companyId))
                throw PARKException.Oh(ErrorCode.D1601);
            var entity = input.Adapt<RoleEntity>();
            entity.CompanyId = userInfo.companyId;
            entity.CompanyName = userInfo.companyName;
            entity.DeleteMark = 0;
            var isOk = await _roleRepository.Context.Insertable(entity).CallEntityMethod(m => m.Creator()).ExecuteReturnEntityAsync();
            _ = isOk ?? throw PARKException.Oh(ErrorCode.D1602);
            await _sysCacheService.DelRole(_userManager.UserId);
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        [HttpDelete("{id}")]
        public async Task Delete(string id)
        {
            var entity = await _roleRepository.FirstOrDefaultAsync(r => r.Id == id && r.DeleteMark == 0);
            _ = entity ?? throw PARKException.Oh(ErrorCode.D1608);
            //角色下有数据权限不能删
            var items = await _authorizeService.GetAuthorizeItemIds(entity.Id, "resource");
            if (await _authorizeService.GetIsExistModuleDataAuthorizeScheme(items.ToArray()))
                throw PARKException.Oh(ErrorCode.D1603);
            //角色下有按钮不能删除
            items = await _authorizeService.GetAuthorizeItemIds(entity.Id, "button");
            if (await _authorizeService.GetIsExistModuleDataAuthorizeScheme(items.ToArray()))
                throw PARKException.Oh(ErrorCode.D1604);
            //角色下有列不能删除
            items = await _authorizeService.GetAuthorizeItemIds(entity.Id, "column");
            if (await _authorizeService.GetIsExistModuleDataAuthorizeScheme(items.ToArray()))
                throw PARKException.Oh(ErrorCode.D1605);
            //角色下有菜单不能删
            items = await _authorizeService.GetAuthorizeItemIds(entity.Id, "module");
            if (await _authorizeService.GetIsExistModuleDataAuthorizeScheme(items.ToArray()))
                throw PARKException.Oh(ErrorCode.D1606);
            //角色下有用户不能删
            if (await _userRelationRepository.AnyAsync(u => u.ObjectType == "Role" && u.ObjectId == id))
                throw PARKException.Oh(ErrorCode.D1607);
            var isOk = await _roleRepository.Context.Updateable<RoleEntity>().SetColumns(it => new RoleEntity()
            {
                DeleteMark = 1,
                DeleteTime = SqlFunc.GetDate(),
                DeleteUserId = _userManager.UserId
            }).Where(it => it.Id == id && it.DeleteMark == 0).ExecuteCommandAsync();
            if (!(isOk > 0)) throw PARKException.Oh(ErrorCode.D1609);
            await _sysCacheService.DelRole(_userManager.UserId);
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="id">主键</param>
        /// <param name="input">参数</param>
        /// <returns></returns>
        [HttpPut("{id}")]
        public async Task Update(string id, [FromBody] RoleUpInput input)
        {
            if (await _roleRepository.AnyAsync(r => r.EnCode == input.enCode && r.DeleteMark == 0 && r.Id != id))
                throw PARKException.Oh(ErrorCode.D1600);
            if (await _roleRepository.AnyAsync(r => r.FullName == input.fullName && r.DeleteMark == 0 && r.Id != id))
                throw PARKException.Oh(ErrorCode.D1601);
            var entity = input.Adapt<RoleEntity>();
            var isOk = await _roleRepository.Context.Updateable(entity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync();
            if (!(isOk > 0)) throw PARKException.Oh(ErrorCode.D1610);
            await _sysCacheService.DelRole(_userManager.UserId);
        }

        /// <summary>
        /// 更新状态
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        [HttpPut("{id}/Actions/State")]
        public async Task UpdateState(string id)
        {
            if (!await _roleRepository.AnyAsync(r => r.Id == id && r.DeleteMark == 0))
                throw PARKException.Oh(ErrorCode.D1608);

            var isOk = await _roleRepository.Context.Updateable<RoleEntity>().SetColumns(it => new RoleEntity()
            {
                EnabledMark = SqlFunc.IIF(it.EnabledMark == 1, 0, 1),
                LastModifyUserId = _userManager.UserId,
                LastModifyTime = SqlFunc.GetDate()
            }).Where(it => it.Id == id).ExecuteCommandAsync();

            if (!(isOk > 0)) throw PARKException.Oh(ErrorCode.D1610);
            await _sysCacheService.DelRole(_userManager.UserId);
        }
        #endregion

        #region PublicMethod
        /// <summary>
        /// 名称
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        [NonAction]
        public string GetName(string ids)
        {
            if (ids.IsNullOrEmpty())
            {
                return "";
            }
            var idList = ids.Split(",").ToList();
            var nameList = new List<string>();
            var roleList = _roleRepository.Entities.Where(x => x.DeleteMark == 0 && x.EnabledMark == 1).ToList();
            foreach (var item in idList)
            {
                var info = roleList.Find(x => x.Id == item);
                if (info != null && info.FullName.IsNotEmptyOrNull())
                {
                    nameList.Add(info.FullName);
                }
            }
            var name = string.Join(",", nameList);
            return name;
        }
        #endregion
    }
}
